

#Brilliant.org Hunger Games prisoner's dilemma algorithm contest submission.
#Author: Greg Hamel (solo)
#Algorithm name: Mr. Karma
#Blog post about the contest: http://hamelg.blogspot.com/2013/07/hunger-games-game-theory-programming.html


'''
Mr. Karma operates on the principle that individuals in a society need to be "nice but not too nice"
to survive. The rationale behind this principle is that slackers will eventually be recognized
for their antisocial behavior and met with high rates of defection, while highly cooperative players will
become targets or "patsies". Both slackers and patsies will eventually die out.

Similar to tit-for-tat, Mr. Karma believes that cooperation should be determined, in part,
by the amount of cooperation it received in the previous round. Mr. Karma also attempts to maintain a
reputation score that is above the average and median for the population, since other players may decide
use those metrics to inform their decisions. When reputation is above the average and the median, Mr. Karma
takes the opportunity to cooperate slightly less than the amount it received in the previous round. If
reputation dips too low, Mr.Karma attempts to increase its reputation to encourage future cooperation,
but only if other players are cooperating at a reasonable rate.

Mr.Karma spreads cooperation randomly. Random cooperation is dangerous in that it does not target and punish
greedy players. Mr. Karma relies on other well-meaning algorithms to punish especially greedy players.
By spreading cooperation randomly, Mr. Karma is able to gain an advantage over other "mostly cooperative" algorithms
that primary target low reputation players.
'''


def hunt_choices(round_number, current_food, current_reputation, m,  player_reputations):


    #Creates a varaible equal to the number of players still alive.
    number_of_players = len(player_reputations)


    #On the first round, create a variable to keep track of the total number of matches played so far.
    #This variable will be used to help determine whether a little bit of extra slacking will cause Mr.Karma to fall
    #Below the average or median reputation.
    if round_number == 1:
        global total_matches
        total_matches = number_of_players


    #If the game comes down to a battle to the death with 1 other player, choose the dominant strategy of slacking.
    if number_of_players == 1:
        return ["s"]


    #If the game is in the first round, cooperate with all other players to establish a high initial reputation.
    if round_number==1:
        return ['h' for player in player_reputations]


    #Creates a list of the proper length for storing output.
    hunt_decisions = player_reputations[:]


    #During rounds 2-5, cooperate with anyone who has cooperated at least 50% of the time.
    #This helps establish a good reputation and punishes greedy players.
    if round_number in range(2,6):
        total_matches+=number_of_players
        for player in range(number_of_players):
            if player_reputations[player] < 0.5:
                hunt_decisions[player] = "s"
            else:
                hunt_decisions[player] = "h"
        return hunt_decisions


    #Calculations to find the average and median reputations of the population.
    average_reputation = sum(player_reputations[:])/float(number_of_players)
    median_reputation = sorted(player_reputations[:])[number_of_players//2]

    #Calculations to determine whehter Mr.Karma is above or below the averages and by how much.
    average_diff = current_reputation-average_reputation
    median_diff = current_reputation-median_reputation

    #Calculates the number of people who cooperated in the last round.
    last_round_coops = food_last_round.count(1)+food_last_round.count(0)


    #When reputation is above the average and median for the population, cooperate based on the
    #level of cooperation from the previous round.
    if average_diff > (number_of_players/total_matches)*(last_round_coops/number_of_players) \
    and median_diff > (number_of_players/total_matches)*(last_round_coops/number_of_players):
        last_round_coops -= 1+ number_of_players//10      #But do some extra slacking if it is not
                                                          #likley to cause Mr.Karma to dip below the average.

    #If Mr.Karma is above the aveage and median, but not my much...
    elif average_diff > 0 and median_diff > 0:
        last_round_coops = last_round_coops  #Don't make any adjustment--be as nice as people were to you last round.


    #If below average or median reputation try to get back into the good graces of other players,
    #but don't try if under 25% of people are cooperating.
    elif last_round_coops >= number_of_players*0.25:
        last_round_coops += 1 + number_of_players//3   #Add a moderate of cooperation to increase reputation.


    #If below average or median repuptation and fewer than 25% cooperated last round, defect against all players.
    else:
        return ['s' for player in player_reputations]


    #If the amount of cooperation last round with adjustments is greater than or equal to the number of players, cooperate
    #with all players.
    if last_round_coops >= number_of_players:
        return ['h' for player in player_reputations]


    #Set total cooperation against other players this round equal to the number of cooperations recieved in the last round
    #with any adjustments. Keep the return array unsorted so that the hunts and slacks are spread randomly to avoid rewarding
    #players with any particular strategy.
    for player in range(0,last_round_coops):
        hunt_decisions[player] = "h"

    #Defect against all players remaining in the player list.
    for player in hunt_decisions:
        if player != "h":
            player = "s"

    #Iterate total_matches.
    total_matches += number_of_players

    #Return final hunting decisions.
    return hunt_decisions


def hunt_outcomes(food_earnings):
    #Create a global variable to track the amount of cooperation recieved in each round.
    global food_last_round
    food_last_round = food_earnings
    pass

def round_end(award, m, number_hunters):
    pass
